package com.cll.learn.rpc.consumer.handler;

import com.cll.learn.rpc.common.dto.RpcResponse;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.ChannelInboundHandlerAdapter;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.util.concurrent.Callable;

/**
 * 描述信息:
 * 客户端进行服务请求的发送
 * 接收服务端的响应
 * @author CLL
 * @version 1.0
 * @date 2020/9/14 15:37
 */
public class RpcConsumerHandler extends ChannelInboundHandlerAdapter implements Callable<Object> {

    private static final Logger logger = LoggerFactory.getLogger(RpcConsumerHandler.class);

    /**
     * 当前对象中使用的通道的处理器的上下文对象
     */
    private ChannelHandlerContext channelHandlerContext;

    /**
     * 接收到的服务端的响应结果
     */
    private RpcResponse rpcResponse;

    /**
     * 发送给服务端的请求参数
     */
    private Object param;

    private volatile boolean isChanged = false;

    /**
     * 连接上服务器之后的初始化操作
     * @param ctx   接收到的通道处理器上下文
     * @throws Exception    发生错误时候的异常
     */
    @Override
    public void channelActive(ChannelHandlerContext ctx) throws Exception {
        logger.info("===>>> channelActive");
        this.channelHandlerContext = ctx;
    }

    /**
     * 收到服务器数据，唤醒等待线程
     * @param ctx 通道处理器上下文
     * @param msg   接收到的服务端的数据
     * @throws Exception 发生错误的时候的异常信息
     */
    @Override
    public synchronized void channelRead(ChannelHandlerContext ctx, Object msg) throws Exception {
        logger.info("===>>> channelRead");
        if (msg instanceof RpcResponse) {
            this.rpcResponse = (RpcResponse) msg;
            notify();
        } else {
            logger.error("****** 客户端接收到未知类型的数据。msg= {}", msg);
        }
    }

    @Override
    public synchronized Object call() throws Exception {
        logger.info("===>>> call");
        if (this.isChanged) {
            logger.info("===>>> send param ");
            this.channelHandlerContext.writeAndFlush(this.param);
            this.isChanged = false;
        }
        wait();
        return this.rpcResponse.getData();
    }

    public void setParam(Object param) {
        this.param = param;
        this.isChanged = true;
    }
}